from ChainBuilder import ChainBuilder
from Fuzzer import Fuzzer
from Ranker import Ranker
from time import time

def remove_html_markup0(s):
    tag = False
    out = ''
    for c in s:
        if c == '<':  # start of markup
            tag = not tag
        elif c == '>':  # end of markup
            tag = False
        elif not tag:
            out += c
    return out

def remove_html_markup1(s):
    """
    The very first version of the function. 
    Contains a bug:        
        <a href=">">link</a> prints "link
    """
    tag = False
    out = ''
    for c in s:
        if c == '<':  # start of markup
            tag = True
        elif c == '>':  # end of markup
            tag = False
        elif not tag:
            out += c
    return out

def remove_html_markup2(s):
    """
    The second version of the function. 
    Contains two bugs:
        "<b>foo</b>" doesn't print the quotes
        <a href="don't">link</a> prints the empty string
    """
    tag = False
    quote = False
    out = ''
    for c in s:
        if c == '<' and not quote:  # start of markup
            tag = True
        elif c == '>' and not quote:  # end of markup
            tag = False
        elif c == '"' or c == "'" and tag:
            quote = not quote
        elif not tag:
            out += c
    return out

def remove_html_markup3(s):
    """
    The third version of the function. 
    Contains one bug:     
        <a href="don't">link</a> prints the empty string
    """
    tag = False
    quote = False
    out = ''
    for c in s:
        if c == '<' and not quote:  # start of markup
            tag = True
        elif c == '>' and not quote:  # end of markup
            tag = False
        elif (c == '"' or c == "'") and tag:
            quote = not quote
        elif not tag:
            out += c
    return out

def remove_html_markup4(s):
    """
    The final version of the function. 
    Contains no bugs, and can thus be used as a reference ;)
    Even though having an oracle that is as powerful as the program under test 
    seemingly defeats the whole purpose, in fact it does not. 
    Consider reimlementation of an existing program in another language, 
    or reverse engineering of a blackboxed application. 
    """
    tag = False
    quote = False
    out = ''
    for c in s:
        if c == '<' and not quote:  # start of markup
            tag = True
        elif c == '>' and not quote:  # end of markup
            tag = False
        elif (c == '"' or c == "'") and tag and not quote:
            quote = c
        elif c == quote:
            quote = False
        elif not tag:
            out += c
    return out

def remove_html_oracle(inp,delivered):
    expected = remove_html_markup4(inp)
    match = expected==delivered
    return 'PASS' if match else 'FAIL'

def mysteryFail(num):
    tmp = 1337 # only for common prefix @UnusedVariable
    if num <= 0:
        return 'FAIL'
    if 10080 % num == 0:
        return 'FAIL'
    return 'PASS'

def mysteryOracle(_,delivered):
    return delivered

functions = [remove_html_markup0, remove_html_markup1, remove_html_markup2,
             remove_html_markup3, remove_html_markup4]

def systemTest():
    rankor = Ranker()
    generator = ChainBuilder(remove_html_markup0, remove_html_oracle)
    f = Fuzzer(['"',"'",'a','b','href','=','<','>','/'],equalizeCoverage=True)
    for i in range(15):
        start = time()
        failing, passing, failCov, passCov = f.getNextPair(remove_html_markup0,remove_html_oracle)
        if not failing:
            print 'a failing run could not be found'
            continue
        if not passing:
            print 'a passing run could not be found'
            continue
        c = generator.getCEChain(failing,passing,failCov,passCov)
        #print c
        if c.getCauseEffectChain():
            rankor.addCEChain(c)
        else: 
            print 'could not build minimal chain!'
        print 'Duration of test %d: %f' % (i+1,time()-start)
    print '########################################'
    bugList = rankor.getOrderedBugList()
    print "Size of BugList:", len(bugList)
    for i in range(len(bugList)):
        bug = bugList[i]
        causeChain = bug.getAnyCauseChain()
        size = bug.size()
        print 
        print 'Bug %d:' % (i+1)
        print 'Number of cause-effect-chains:', size
        print 'Size of shown cause-effect-chain:', len(causeChain)
        for j in range(len(causeChain)):
            print repr(causeChain[j])

if __name__ == '__main__':
    systemTest()
    #import cProfile
    #cProfile.run('systemTest()', 'stats.txt')